from PyQt6 import QtWidgets, QtCore
from PyQt6.QtCore import pyqtSlot, QObject, Qt, QSize
from PyQt6.QtGui import QFont, QTextCharFormat, QTextCursor, QColor, QPixmap
import sys
import os
from dobot_arm_set import arm_set
from Ui_main import Ui_Dialog
from tcp_connect import tcp_con_cfg
from inforamtion_lists import information_lists
import logging
from log_config import init_logging
import tcp_client
import arm_ctrl
from ftp_server import SimpleFTPServer  # 引入你封装好的ftp模块

class Communicate(QObject):
    image_received = QtCore.pyqtSignal(str, bytes)  # cam_id, img_data


class QPlainTextEditHandler(logging.Handler, QtCore.QObject):
    log_signal = QtCore.pyqtSignal(logging.LogRecord)

    def __init__(self, widget: QtWidgets.QPlainTextEdit):
        QtCore.QObject.__init__(self)
        logging.Handler.__init__(self)
        self.widget = widget
        self.log_signal.connect(self.append_log)

    def emit(self, record):
        self.log_signal.emit(record)

    @QtCore.pyqtSlot(logging.LogRecord)
    def append_log(self, record):
        msg = self.format(record)
        cursor = self.widget.textCursor()
        cursor.movePosition(QTextCursor.MoveOperation.End)

        fmt = QTextCharFormat()
        level = record.levelno

        # 设置不同日志等级的颜色
        if level >= logging.CRITICAL:
            fmt.setForeground(QColor('darkred'))
            fmt.setFontWeight(QFont.Weight.Bold)
        elif level >= logging.ERROR:
            fmt.setForeground(QColor('red'))
        elif level >= logging.WARNING:
            fmt.setForeground(QColor('orange'))
        elif level >= logging.INFO:
            fmt.setForeground(QColor('black'))
        else:  # DEBUG
            fmt.setForeground(QColor('gray'))

        cursor.insertText(msg + '\n', fmt)
        self.widget.setTextCursor(cursor)
        self.widget.ensureCursorVisible()

class MainDialog(QtWidgets.QDialog, Ui_Dialog):
    def __init__(self):
        super().__init__()
        self.child_windows = []
        self.ui = Ui_Dialog()
        self.ui.setupUi(self)
        self.arm_state = False
        self.init_ui_logic()
        self.step_size = None
        # 添加日志输出绑定
        self.init_logging_output()
        self.config_data = None
        self.dashboard = None
        self.moved = None
        self.feed = None
        # MainWindow.__init__ 中添加：
        self.comm = Communicate()
        self.comm.image_received.connect(self.update_image)

        self.ftp_server = SimpleFTPServer("./mnt/data/tmp_ftp")
        self.ftp_server.start()

        
        

        # 示例输出一条日志
        logging.info("Main dialog initialized")

    def init_logging_output(self):
        handler = QPlainTextEditHandler(self.ui.plainTextEdit)
        formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
        handler.setFormatter(formatter)
        init_logging(handler)


    def init_ui_logic(self):
        self.ui.pushButton.clicked.connect(self.open_IP_setting_window)
        self.ui.pushButton_12.clicked.connect(self.infor_window)
        self.ui.pushButton_13.clicked.connect(self.open_arm_set_dialog)
        self.ui.lineEdit.editingFinished.connect(self.Set_arm_step_size)
        self.ui.pushButton_2.clicked.connect(self.arm_enable_disable)
        self.ui.pushButton_3.clicked.connect(self.arm_x_add)
        self.ui.pushButton_4.clicked.connect(self.arm_x_sub)
        self.ui.pushButton_5.clicked.connect(self.arm_y_add)
        self.ui.pushButton_6.clicked.connect(self.arm_y_sub)
        self.ui.pushButton_7.clicked.connect(self.arm_z_add)
        self.ui.pushButton_8.clicked.connect(self.arm_z_sub)
        self.ui.pushButton_9.clicked.connect(self.arm_r_add)
        self.ui.pushButton_10.clicked.connect(self.arm_r_sub)
        self.ui.pushButton_11.clicked.connect(self.arm_run_coordinates)

    @pyqtSlot()
    def open_IP_setting_window(self):
        dlg = tcp_con_cfg.run()
        dlg.config_applied.connect(self.on_ip_config_applied)  # 连接信号
        self.child_windows.append(dlg)  # 如有需要记录窗口
        dlg.exec()  # 模态打开，阻塞直到关闭

    def on_ip_config_applied(self, config):
        self.config_data = config  
        logging.info(f"TCP connection config applied: {config}")
        self.conmutation_connect()  # 连接设备

    def set_ip_mapping(self):
        ip1 = self.config_data['camera_1']['ip'].strip()
        ip2 = self.config_data['camera_2']['ip'].strip()
        ip_map = {}
        if ip1:
            ip_map[ip1] = "cam1"
        if ip2:
            ip_map[ip2] = "cam2"
        print(f"[UI] 设置 IP 映射: {ip_map}")
        self.ftp_server.set_ip_cam_map(ip_map)
        self.ftp_server.on_image_received = lambda cam_id, img: self.comm.image_received.emit(cam_id, img)
        self.ftp_server.start()     

    def conmutation_connect(self):
        if self.config_data is not None:
            logging.info("TCP connection start")
            # 连接设备摄像头1
            if bool(self.config_data["camera_1"]["mode"]) == True:
                logging.info(f"Camera_1 ip: {self.config_data['camera_1']['ip']}, port: {self.config_data['camera_1']['data_port']}, mode: {self.config_data['camera_1']['mode']}")
                logging.info(f"Begin tcp connection camera_1")
                try:
                    self.camera_1_data = tcp_client.TCPClient(self.config_data["camera_1"]["ip"], self.config_data["camera_1"]["data_port"], mode='text')
                    self.camera_1_data.connect()
                    self.ui.label.setText("摄像头1已连接")
                    logging.info("TCP connection camera_1 done")
                except Exception as e:
                    logging.error(f"Tcp connection camera_1 failed: {e}")
            else:
                logging.info("Camera_1 not enabled")
            # 连接设备摄像头2
            if bool(self.config_data["camera_2"]["mode"]) == True:
                logging.info(f"Camera_2 ip: {self.config_data['camera_2']['ip']}, port: {self.config_data['camera_2']['data_port']}, mode: {self.config_data['camera_2']['mode']}")
                logging.info(f"Begin tcp connection camera_2")
                try:
                    self.camera_2_data = tcp_client.TCPClient(self.config_data["camera_2"]["ip"], self.config_data["camera_2"]["data_port"], mode='text')
                    self.camera_2_data.connect()
                    self.ui.label_2.setText("摄像头2已连接")
                    logging.info("Tcp connection camera_2 done")
                except Exception as e:
                    logging.error(f"Tcp connection camera_2 failed: {e}")
            else:
                logging.info("Camera_2 not enabled")
            if bool(self.config_data["dobot"]["mode"]) == True:
                logging.info(f"Arm ip: {self.config_data['dobot']['ip']}, dashboard_port: {self.config_data['dobot']['dashboard_port']}, move_port: {self.config_data['dobot']['move_port']}, feed_port: {self.config_data['dobot']['feed_port']}, mode: {self.config_data['dobot']['mode']}")
                logging.info(f"Begin arm connection")
            # 连接机械臂
                try:
                    self.dashboard, self.moved, self.feed = arm_ctrl.ConnectRobot(self.config_data["dobot"]["ip"], self.config_data["dobot"]["dashboard_port"], self.config_data["dobot"]["move_port"], self.config_data["dobot"]["feed_port"])
                    self.ui.label_6.setText("机械臂已连接")
                    logging.info("Arm connection done")
                except Exception as e:
                    logging.error(f"Arm connection failed: {e}")
            else:
                logging.info("Arm not enabled")
            self.set_ip_mapping()
            
        else:
            logging.error("TCP connection config not applied")

     


    @pyqtSlot()
    def open_arm_set_dialog(self):
        dlg = arm_set.run()
        self.child_windows.append(dlg)
    @pyqtSlot()
    def infor_window(self):
        dlg = information_lists.run()
        self.child_windows.append(dlg)
    @pyqtSlot()
    def Set_arm_step_size(self):
        self.step_size = int(self.ui.lineEdit.text())
        logging.info(f"Set arm step size to {self.step_size}")
    @pyqtSlot()
    def arm_enable_disable(self):
        if self.arm_state == False:
            arm_ctrl.enable()
            self.ui.label_6.setText("机械臂已使能")
            self.ui.pushButton_2.setText("去使能机械臂")

            logging.info("Arm enable done")
        elif self.arm_state == True:
            arm_ctrl.disable()
            self.ui.label_6.setText("机械臂未使能")
            self.ui.pushButton_2.setText("使能机械臂")
            logging.info("Arm disable done")
        self.arm_state = not self.arm_state
    @pyqtSlot()
    def arm_x_add(self):
        if self.step_size is not None:
            logging.info(f"Arm x add with step size {self.step_size}")
        else:
            logging.warning("Arm step size not set")
    @pyqtSlot()
    def arm_x_sub(self):
        if self.step_size is not None:
            logging.info(f"Arm x sub with step size {self.step_size}")
        else:
            logging.warning("Arm step size not set")
    @pyqtSlot()
    def arm_y_add(self):
        if self.step_size is not None:
            logging.info(f"Arm y add with step size {self.step_size}")
        else:
            logging.warning("Arm step size not set")
    @pyqtSlot()
    def arm_y_sub(self):
        if self.step_size is not None:
            logging.info(f"Arm y sub with step size {self.step_size}")
        else:
            logging.warning("Arm step size not set")
    @pyqtSlot()
    def arm_z_add(self):
        if self.step_size is not None:
            logging.info(f"Arm z add with step size {self.step_size}")
        else:
            logging.warning("Arm step size not set")
    @pyqtSlot()
    def arm_z_sub(self):
        if self.step_size is not None:
            logging.info(f"Arm z sub with step size {self.step_size}")
        else:
            logging.warning("Arm step size not set")
    @pyqtSlot()
    def arm_r_add(self):
        if self.step_size is not None:
            logging.info(f"Arm r add with step size {self.step_size}")
        else:
            logging.warning("Arm step size not set")
    @pyqtSlot()
    def arm_r_sub(self):
        if self.step_size is not None:
            logging.info(f"Arm r sub with step size {self.step_size}")
        else:
            logging.warning("Arm step size not set")
    @pyqtSlot()
    def arm_run_coordinates(self):
        if self.ui.checkBox.isChecked():
            #相对运动模式
            arm_ctrl.move_rel(float(self.ui.lineEdit_2.text()),float(self.ui.lineEdit_3.text()),float(self.ui.lineEdit_4.text()))
            logging.info(f"Arm move to {self.ui.lineEdit_2.text()} {self.ui.lineEdit_3.text()} {self.ui.lineEdit_4.text()} with relative mode")
        else:
            #绝对运动模式
            arm_ctrl.move_abs(float(self.ui.lineEdit_2.text()),float(self.ui.lineEdit_3.text()),float(self.ui.lineEdit_4.text()))
            logging.info(f"Arm move to {self.ui.lineEdit_2.text()} {self.ui.lineEdit_3.text()} {self.ui.lineEdit_4.text()} with absolute mode")

    def update_image(self, cam_id: str, img_bytes: bytes):
        pixmap = QPixmap()
        if not pixmap.loadFromData(img_bytes):
            logging.error(f"[UI] {cam_id} 图片加载失败")
            return

        label = None
        if cam_id == "cam1":
            label = self.ui.label_4
        elif cam_id == "cam2":
            label = self.ui.label_5
        else:
            logging.error(f"[UI] 未知摄像头ID: {cam_id}")
            return

        # 获取 label 尺寸（支持高DPI 缩放）
        target_size: QSize = label.size() * self.devicePixelRatioF()

        # 使用高质量缩放，保持图像比例
        scaled_pixmap = pixmap.scaled(
            target_size,
            Qt.AspectRatioMode.KeepAspectRatio,
            Qt.TransformationMode.SmoothTransformation  # 提高缩放质量
        )

        label.setPixmap(scaled_pixmap)


# 启动程序
if __name__ == "__main__":
    os.environ["QT_AUTO_SCREEN_SCALE_FACTOR"] = "1"

    app = QtWidgets.QApplication(sys.argv)

    # 可选：根据 DPI 缩放字体
    screen = app.primaryScreen()
    dpi = screen.logicalDotsPerInch()
    scale = dpi / 96.0
    font = QFont("Microsoft YaHei", int(10 * scale))
    app.setFont(font)

    dlg = MainDialog()
    dlg.show()
    sys.exit(app.exec())
